package fr.umlv.m2.ig.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;

import javax.swing.table.AbstractTableModel;

/**
 * This class defines the stations table model.
 * 
 * @author Gambouele Bertrand.
 * @author Viravout Alexandre.
 */
@SuppressWarnings("serial")
public class StationsTableModel extends AbstractTableModel {
  /**
   * This enumeration defines the ways to display stations.
   * 
   * @author Gambouele Bertrand.
   * @author Viravout ALexandre.
   */
  public enum DisplayWay { NONE, LINE, NAME };

  /**
   * Beauheur model.
   */
  private BeauheurModelImpl model;

  /**
   * The rail network.
   */
  private Map<String, List<String>> railNatwork;

  /**
   * The lines.
   */
  private List<String> lines;
  /**
   * The lines displayed on a search by name.
   */
  private List<String> displayLines;

  /**
   * The stations.
   */
  private List<String> stations;
  /**
   * The stations displayed on a search by name.
   */
  private List<String> displayStations;

  /**
   * The stations table model column names.
   */
  private static String[] columnNames;

  /**
   * The line whose stations will be displayed.
   */
  private String line;

  /**
   * The way to display stations.
   */
  private DisplayWay displayStationsWay;

  /**
   * Create a StationsTableModel object.
   * 
   * @param model the application model.
   */
  public StationsTableModel(BeauheurModelImpl model) {
    this.model = model;

    this.railNatwork = new HashMap<String, List<String>>();
    this.lines = new ArrayList<String>();
    this.stations = new ArrayList<String>();

    columnNames = new String[]{ "Ligne", "Station" };
    this.displayStationsWay = DisplayWay.NONE;

    Iterator<Entry<String, Line>> lineIt = this.model.getLines().entrySet().iterator();
    Iterator<Entry<String, Station>> stationIt = this.model.getStations().entrySet().iterator();

    Line line;
    Station station; 
    while(lineIt.hasNext()) {
      line = lineIt.next().getValue();
      this.railNatwork.put(line.getName(), new ArrayList<String>());
    }

    List<String> lines;
    while(stationIt.hasNext()) {
      station = stationIt.next().getValue();
      if(station.getType() == StationType.CURVE) {
        continue;
      }

      for(String lineName : station.getLines()) {
        lines = this.railNatwork.get(lineName);
        lines.add(station.getName());
        this.railNatwork.put(lineName, lines);

        this.lines.add(lineName);
        this.stations.add(station.getName());
      }
    }
  }

  @Override
  public int getColumnCount() {
    return columnNames.length;
  }

  @Override
  public String getColumnName(int column) {
    return columnNames[column];
  }

  @Override
  public int getRowCount() {
    switch(this.displayStationsWay) {
    case NONE: return this.stations.size();
    case LINE: return this.railNatwork.get(this.line).size();
    case NAME: return this.displayStations.size();
    default:
      throw new IllegalArgumentException("Invalid display stations way: " + this.displayStationsWay);
    }
  }

  @Override
  public Object getValueAt(int rowIndex, int columnIndex) {    
    if(this.displayStationsWay == DisplayWay.LINE) {
      switch(columnIndex) {
      case 0 : return this.line;
      case 1 : return this.railNatwork.get(this.line).get(rowIndex);
      default: throw new IllegalArgumentException("Invalid column index: " + columnIndex);
      }
    } else if(this.displayStationsWay == DisplayWay.NAME) {
      switch(columnIndex) {
      case 0 : return this.displayLines.get(rowIndex);
      case 1 : return this.displayStations.get(rowIndex);
      default: throw new IllegalArgumentException("Invalid column index: " + columnIndex);
      }
    } else {
      switch(columnIndex) {
      case 0 : return this.lines.get(rowIndex);
      case 1 : return this.stations.get(rowIndex);
      default: throw new IllegalArgumentException("Invalid column index: " + columnIndex);
      }
    }
  }

  /**
   * Sets the line whose stations will be displayed.
   * 
   * @param line the line name.
   */
  public void setLine(String line) {
    if(line.isEmpty()) {
      this.displayStationsWay = DisplayWay.NONE;
    } else {
      this.line = line;
      this.displayStationsWay = DisplayWay.LINE;
    }
  }

  /**
   * Initialization of filtered list.
   * 
   * @param name the station name.
   */
  public void initFilteredList(String name) {
    String stationName = name.replaceAll("\\s", "");
    if(stationName.length() > 0) {
      this.displayStationsWay = DisplayWay.NAME;

      String interval1 = name;
      String interval2 = interval1.substring(0, interval1.length()-1);
      char c = interval1.charAt(interval1.length()-1);
      interval2 += ++c;

      SortedMap<String, Station> stations = (SortedMap<String, Station>) model.getStations();
      Map<String, Station> filterStations = stations.subMap(interval1, interval2);

      Iterator<Entry<String, Station>> stationsIt = filterStations.entrySet().iterator();

      Station station;
      this.displayLines = new ArrayList<String>();
      this.displayStations = new ArrayList<String>();
      while(stationsIt.hasNext()) {
        station = stationsIt.next().getValue();
        if(station.getType() == StationType.CURVE) {
          continue;
        }

        for(String lineName : station.getLines()) {
          this.displayLines.add(lineName);
          this.displayStations.add(station.getName());
        }
      }
    } else {
      this.displayStationsWay = DisplayWay.NONE;
    }
  }
}
